/**
 * Student Name: Philippe Gambling
 * Course: CSCI 5733
 * Section: 01
 * Student Number: 0603418
 * Assignment: Homework 2
 * Requirements: http://dcm.uhcl.edu/yue/courses/xml/summer2009/hw/h2.html
 * Filename: UniqueNamePathDepthDom.java
 * Descriptions: Counts the maximum unique element names in a single path using the DOM API.
 * 
 */

import java.io.File;
import java.util.HashSet;
import java.util.Stack;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.TreeWalker;

/**
 * @author Philippe Gambling
 *
 */
public class UniqueNamePathDepthDom {

	// Data Members
	private static Document document;
	private static TreeWalker walker;
	private static int numUnique = 0;
	private static Stack<String> elementsInPath = new Stack<String>();
	
	/**
	 * @param argv
	 */
	public static void main(String[] argv) {
        if (argv.length != 1) {
            System.err.println("Usage: UniqueNamePathDepthDom filename");
            System.exit(1);
        }
	
        String filename = argv[0];
               
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
           DocumentBuilder builder = factory.newDocumentBuilder();
           document = builder.parse( new File(argv[0]) );
		   
        } catch (Throwable e) {
           e.printStackTrace();
        }
        
        // Set up a tree walker that filters out all nodes EXCEPT elements
        DocumentTraversal traversable = (DocumentTraversal) document;
        walker = traversable.createTreeWalker(document.getDocumentElement(), NodeFilter.SHOW_ELEMENT, null , false);
        
        processNode(walker.getRoot());
        
        System.out.println("The maximum number of distinct element names in the paths in " 
        		           + filename + " is " + numUnique + ".");
	}

	/**
	 * Recursively traverses the document tree and counts up the unique elements in each path.
	 * 
	 * @param node
	 */
	private static void processNode(Node node) {
		if(node == null) { // Arrived at end of a path, count the number unique elements
			int numUniqueInPath = (new HashSet<String>(elementsInPath)).size();
			numUnique = (numUniqueInPath>numUnique) ? numUniqueInPath:numUnique;
			return;
		} else { // Add current element name to this path
		  elementsInPath.push(node.getNodeName());
		}
		
		// Process the first child of this node
		processNode(walker.firstChild());
		
		// Remove this leaf from current path 
		// and continue with next sibling node if exists
		elementsInPath.pop();
		if(walker.nextSibling() != null) processNode(walker.getCurrentNode());
		walker.parentNode();
	}
}
